在 google 跑分時總是會出現,xxx.chunk.js 太肥囉,要該減肥一下呦,順便去除沒有用到的東西
然後基於你是 react 框架,如果不使用 SSR 推薦你使用 React.lazy()
或是處理 code-split 可以使用 loadable-components
好,所以我們的目標是把大大的 main.xxx.chunk.js
code-split 拆分掉
react bundle analyzer
source-map-explorer
在處理 bundle 之前,先安裝可以看清楚 bundle 畫面的 package create-react-app 官方(Analyzing the Bundle Size)是用 source-map-explorer
在外面看到大部分人都用 webpack-bundle-analyzer 但這篇文章(Revisit the decision to allow webpack analyzer tools)似乎是有說他有標籤標記錯誤的問題,但是裡面也有很多人舉例說為啥他會愛 webpack-bundle-analyzer
勝過於 source-map-explorer 的原因 😂
$npm i -D source-map-explorer
在 package.json
新增一條 script
//package.json
"scripts": {
"analyze": "source-map-explorer 'build/static/js/*.js'",
}
在執行 build 跟 analyze
$npm run build
$npm run analyze
也可以改寫成這樣
"analyze": "npm run build && npm run analyze-bundle",
"analyze-bundle": "source-map-explorer 'build/static/js/*.js'"
這樣只要跑一行指令就好了
$npm run analyze
webpack-bundle-analyzer
不 eject CRA 狀態下用 webpack-bundle-analyzer
$npm i -D webpack-bundle-analyzer
//package.json
{
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build --stats && webpack-bundle-analyzer build/bundle-stats.json -m static -r build/bundle-stats.html -O",
"test": "react-scripts test"
}
}
測試了很久都沒有成功,後來找到文件說
Using webpack-bundle-analyzer has been deprecated an the flag `—-stats` has been removed in CRA v3. You should be using source-map-explorer instead by running: `npm i -g source-map-explorer`and `source-map-explorer 'build/static/js/*.js'`.
The following paragraph is deprecated:
原本可以用 --stats
來生出 bundle-stats.json
但看起來 CRA 就是要推廣 source-map-explorer
整個拿掉沒辦法在不 eject 狀態下用惹QQ
react-loadable
react 在做 code-split 也可以針對 react-router 做處理
react-router 官方文件是推薦使用 loadable-component
但看仿間大多人都使用 react-loadable
$npm i react-loadable
import Loadable from "react-loadable";
import Loading from "./my-loading-component";
const LoadableComponent = Loadable({
loader: () => import("./my-component"),
loading: Loading,
});
export default class App extends React.Component {
render() {
return <LoadableComponent />;
}
}
Dynamic imports 寫法
這邊預設 function 是 export default ,但我通常都只有 export const 所以這邊 import 要改寫成
const LoadableComponent = Loadable({
loader: () => import("./my-component").then(({ Component }) => Component),
loading: Loading,
});
但測試後發現,怎麼 chunck 沒有分開?!!原因是因為我都在同一個 index.js 通通 export 所以他一樣會包在一起
發現這篇文章也有一樣的問題 Code splitting with create-react-app and react-loadable is not working
因為在該 index.js
頁面就已經全部都合在一起了,所以要把這邊 index.js
mark 掉,然後 import 分開寫,如果 index.js
沒有 mark 掉,即使引入分開寫,也一樣會包在一起不會分開歐
named chunks.js
如果想要 name chunks.js 檔案的話,可以這樣做設定
const Policies = Loadable({
loading: PageLoading,
loader: () =>
import(
/* webpackChunkName: "policies" */
"pages/Policies"
).then((module) => module.Policies),
});
原本是 2.chunk.js 就會命名稱 policies.chunk.js
create-react-app 的 webpack 有設定這功能,如果沒有反應的話要去 wepback 的 config 檔,新增下面的設定
output: {
path: path.join(__dirname, './../public'),
filename: 'bundle.js',
publicPath: '/',
chunkFilename: '[name].[chunkhash].js'
},
result
原本 main chunk 427.04 kb 占 38%
code-split 後 342.34kb 占 27.3%
origin
after
React.lazy
如果只用 react 原生的 lazy 也可以達到 code-split 的效果
import React, { Suspense, lazy } from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import { Home } from "./components/Home";
export const Routes = () => {
return (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route
path="/about"
component={lazy(() =>
import(/* webpackChunkName: "about" */ "./components/About")
)}
/>
<Route path="/" component={Home} />
</Switch>
</Suspense>
</Router>
);
};
trouble shooting
用 react lazy 的話,他只接受 const MyComponent = lazy(() => import('./MyComponent'))
的格式
所以要 export default
❌
export const About = () => {
return (
<div>
About<Link to="/">Home</Link>
</div>
);
};
⭕️
let About;
export default About = () => {
return (
<div>
About<Link to="/">Home</Link>
</div>
);
};
[reference]
bundle
loadable
React Loadable — SSR and Code-Splitting
使用 React-loadable 在 React 應用中實現 Code Splitting
Code Splitting in React using React Loadable | Load code On demand
dynamic import
webpackChunkName
把已開發好的專案新增 code-split 真的比一開始開發就加上去來的還有跳戰性啊~!!